x86/mm: New mem access type to log access
authorAndres Lagar-Cavilla <andres@lagarcavilla.org>
Tue, 6 Dec 2011 21:16:56 +0000 (21:16 +0000)
committerAndres Lagar-Cavilla <andres@lagarcavilla.org>
Tue, 6 Dec 2011 21:16:56 +0000 (21:16 +0000)
This patch adds a new p2m access type, n2rwx. It allows for implement a "log
access" mode in the hypervisor, akin to log dirty but for all types of
accesses. Faults caused by this access mode automatically promote the
access rights of the offending p2m entry, place the event in the ring, and
let the vcpu keep on executing.

Signed-off-by: Andres Lagar-Cavilla <andres@lagarcavilla.org>
Signed-off-by: Adin Scannell <adin@scannell.ca>
Acked-by: Tim Deegan <tim@xen.org>
Committed-by: Tim Deegan <tim@xen.org>
xen/arch/x86/hvm/hvm.c
xen/arch/x86/mm/p2m-ept.c
xen/arch/x86/mm/p2m.c
xen/include/asm-x86/p2m.h
xen/include/public/hvm/hvm_op.h

index 0a63af88f25a91ee621455df5fed87ea17fcbac0..901132d25e506d08c29623e3ad99a3f30bfad19d 100644 (file)
@@ -1250,6 +1250,7 @@ int hvm_hap_nested_page_fault(unsigned long gpa,
         switch (p2ma) 
         {
         case p2m_access_n:
+        case p2m_access_n2rwx:
         default:
             violation = access_r || access_w || access_x;
             break;
index c657a106d7d224b6ddecbf72df8dfdaad7e00d20..f31558e45c9023c5534f233efc11e3462c922245 100644 (file)
@@ -111,6 +111,7 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces
     switch (access) 
     {
         case p2m_access_n:
+        case p2m_access_n2rwx:
             entry->r = entry->w = entry->x = 0;
             break;
         case p2m_access_r:
index fe937045496ad46b04e133e875bfb0140894fbaa..d90c6deeba92941f93e5f0dde83cc56317fd4b94 100644 (file)
@@ -1107,6 +1107,11 @@ bool_t p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long g
         p2m_unlock(p2m);
         return 1;
     }
+    else if ( p2ma == p2m_access_n2rwx )
+    {
+        ASSERT(access_w || access_r || access_x);
+        p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rwx);
+    }
     p2m_unlock(p2m);
 
     /* Otherwise, check if there is a memory event listener, and send the message along */
@@ -1124,10 +1129,13 @@ bool_t p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long g
         }
         else
         {
-            /* A listener is not required, so clear the access restrictions */
-            p2m_lock(p2m);
-            p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rwx);
-            p2m_unlock(p2m);
+            if ( p2ma != p2m_access_n2rwx )
+            {
+                /* A listener is not required, so clear the access restrictions */
+                p2m_lock(p2m);
+                p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rwx);
+                p2m_unlock(p2m);
+            }
             return 1;
         }
 
@@ -1140,9 +1148,12 @@ bool_t p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long g
     req.type = MEM_EVENT_TYPE_ACCESS;
     req.reason = MEM_EVENT_REASON_VIOLATION;
 
-    /* Pause the current VCPU unconditionally */
-    vcpu_pause_nosync(v);
-    req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED;    
+    /* Pause the current VCPU */
+    if ( p2ma != p2m_access_n2rwx )
+    {
+        vcpu_pause_nosync(v);
+        req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED;
+    } 
 
     /* Send request to mem event */
     req.gfn = gfn;
@@ -1157,8 +1168,8 @@ bool_t p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long g
 
     mem_event_put_request(d, &d->mem_event->access, &req);
 
-    /* VCPU paused, mem event request sent */
-    return 0;
+    /* VCPU may be paused, return whether we promoted automatically */
+    return (p2ma == p2m_access_n2rwx);
 }
 
 void p2m_mem_access_resume(struct domain *d)
@@ -1204,6 +1215,7 @@ int p2m_set_mem_access(struct domain *d, unsigned long start_pfn,
         p2m_access_wx,
         p2m_access_rwx,
         p2m_access_rx2rw,
+        p2m_access_n2rwx,
         p2m->default_access,
     };
 
index 2e174bf184d4db87ccc2ba13b209ca6c4db503f5..826914442403119c5c4fef27541cc125b2c1ff78 100644 (file)
@@ -108,6 +108,9 @@ typedef enum {
     p2m_access_wx    = 6, 
     p2m_access_rwx   = 7,
     p2m_access_rx2rw = 8, /* Special: page goes from RX to RW on write */
+    p2m_access_n2rwx = 9, /* Special: page goes from N to RWX on access, *
+                           * generates an event but does not pause the
+                           * vcpu */
 
     /* NOTE: Assumed to be only 4 bits right now */
 } p2m_access_t;
index 1689cd22d69ed62a5e1d5542592b59afd0855e63..6a78f757d5a1f43b86bef7d6b96d5fb0e3084d10 100644 (file)
@@ -174,6 +174,9 @@ typedef enum {
     HVMMEM_access_rwx,
     HVMMEM_access_rx2rw,       /* Page starts off as r-x, but automatically
                                 * change to r-w on a write */
+    HVMMEM_access_n2rwx,       /* Log access: starts off as n, automatically 
+                                * goes to rwx, generating an event without
+                                * pausing the vcpu */
     HVMMEM_access_default      /* Take the domain default */
 } hvmmem_access_t;
 /* Notify that a region of memory is to have specific access types */